﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Urb.Weather.Core.Util
{
    /// <summary>
    /// Handles string representation of date/time as described in RFC 822
    /// Taken from: http://dev-ua.com/index.php?showtopic=424
    /// </summary>
    public static class Rfc822DateTime
    {
        /// <summary>
        /// Parses date/time in RFC 822
        /// </summary>
        /// <param name="date">String to parse</param>
        /// <returns>Parsed date time offset</returns>
        /// <exception cref="FormatException">If string is not valid RFC 822 date time</exception>
        public static DateTimeOffset Parse(string date)
        {
            DateTimeOffset result;
            if (!TryParse(date, out result))
            {
                throw new FormatException("String is not valid ");
            }
            return result;
        }

        /// <summary>
        /// Tries to parse date-time string in RFC 822.
        /// </summary>
        /// <param name="date">String to parse</param>
        /// <param name="result">If string is valid - result of parsing, </param>
        /// <returns>True, if string is valid RFC 822, False either</returns>
        public static bool TryParse(string date, out DateTimeOffset result)
        {
            //This handles numeric timeshifts (like +0200 or -1030)
            //And also GMT and Z, so they are excluded from next code
            if (DateTimeOffset.TryParse(date, out result))
            {
                return true;
            }

            //We failed to parse time directly - now trying to parse RFC time zones
            int pos = date.LastIndexOf(" ");
            string zone = date.Substring(pos + 1).ToUpper().Trim();
            string body = date.Substring(0, pos);

            DateTime resultBody;
            if (!DateTime.TryParse(body, out resultBody))
            {
                return false;
            }

            TimeSpan shift;

            if (zone.Length == 1)
            //Military format. Regardless this format is described in RFC with mistake (wrong sign of shift),
            //so deprecated in RFC 1123 and 2822, standard declares it - so we implement.
            {
                char zoneChar = zone[0];
                int shiftHours;

                if (!Char.IsLetter(zoneChar) || zoneChar == 'J')
                {
                    return false;
                }
                else if (zoneChar < 'N') //negative shift
                {
                    if (zoneChar > 'J') // 'J' is skipped
                    {
                        zoneChar--;
                    }
                    shiftHours = 'A' - 1 - zoneChar;
                }
                else //positive shift
                {
                    shiftHours = zoneChar - 'M';
                }
                shift = new TimeSpan(shiftHours, 0, 0);
            }
            else if (zone == "UT" || zone == "UTC")
            {
                shift = new TimeSpan(0, 0, 0);
            }
            else
            {
                int shiftHours = 0;
                
                switch (zone)
                {
                    case "BST":
                        shiftHours = 1; break;
                    case "CEST":
                        shiftHours = 2; break;
                    case "CET":
                        shiftHours = 1; break;
                    case "EEST":
                        shiftHours = 3; break;
                    case "EET":
                        shiftHours = 2; break;
                    case "GMT":
                        shiftHours = 0; break;
                    case "IST":
                        shiftHours = 1; break;
                    case "KUYT":
                        shiftHours = 4; break;
                    case "MSD":
                        shiftHours = 4; break;
                    case "MSK":
                        shiftHours = 3; break;
                    case "SAMT":
                        shiftHours = 4; break;
                    case "WEST":
                        shiftHours = 1; break;
                    case "WET":
                        shiftHours = 0; break;
                }

                shift = new TimeSpan(shiftHours, 0, 0);
            }
            result = new DateTimeOffset(resultBody, shift);
            return true;
        }
    }
}
